package outbound_crowd

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"git.mycaigou.com/gfyx/common/authorize"
	"git.mycaigou.com/gfyx/common/simplecopier"
	"git.mycaigou.com/gfyx/common/tenant_db"
	"git.mycaigou.com/gfyx/common/usermetadata"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/common/constants"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/common/errcode"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/common/ossfile"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/common/utils"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/business_opportunity/contact"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/common/file"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/market/outbound_crowd"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/remote/baiying_remote"
	bigdataRemote "git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/remote/bigdata_remote"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/remote/opensearch_remote"
	pb "git.mycaigou.com/gfyx/micro-gfyx-oppty-service/proto/micro_gfyx_oppty_service_proto/micro-gfyx-oppty-service/market"
	"git.myscrm.cn/golang/common/ykerrcode"
	"git.myscrm.cn/golang/stark/v4"
	"io"
	"net/http"
	"strings"
	"sync"
	"time"
)

type outboundCrowdService struct {
	openSearchRepos       opensearch_remote.OpenSearchRepositoryIface
	bigDataServiceRepo    bigdataRemote.BigDataServiceRepositoryIface
	outboundCrowdRepos    outbound_crowd.OutboundCrowdReposIface
	fileRepo              file.FileRepoIface
	opTelViewHistoryRepos contact.GfyxOpTelViewHistoryReposIface
}

func NewOutboundCrowdService(
	openSearchRepos opensearch_remote.OpenSearchRepositoryIface,
	bigDataServiceRepo bigdataRemote.BigDataServiceRepositoryIface,
	outboundCrowdRepos outbound_crowd.OutboundCrowdReposIface,
	fileRepo file.FileRepoIface,
	opTelViewHistoryRepos contact.GfyxOpTelViewHistoryReposIface,
) OutboundCrowdServiceIface {
	return &outboundCrowdService{
		openSearchRepos:       openSearchRepos,
		bigDataServiceRepo:    bigDataServiceRepo,
		outboundCrowdRepos:    outboundCrowdRepos,
		fileRepo:              fileRepo,
		opTelViewHistoryRepos: opTelViewHistoryRepos,
	}
}

// GetCrowdList 人群列表
func (s *outboundCrowdService) GetCrowdList(ctx context.Context, request *pb.GetCrowdListRequest) (*pb.GetCrowdListResponse, error) {
	condition := &outbound_crowd.GetCrowdListCondition{
		CrowdName: request.CrowdName,
		Status:    request.Status,
	}
	crowdList, total, err := s.outboundCrowdRepos.GetOutboundCrowdPage(ctx, condition, request.Page, request.PageSize)
	if err != nil {
		stark.Logger.Errorf(ctx, "GetCrowdList 获取人群列表,err:%s", err.Error())
	}
	res := &pb.GetCrowdListResponse{
		Total: total,
	}
	GetCrowdList := make([]*pb.GetCrowd, 0)
	for _, item := range crowdList {
		data := s.dealCrowdData(item)
		GetCrowdList = append(GetCrowdList, data)
	}
	res.List = GetCrowdList
	return res, nil
}

func (s *outboundCrowdService) dealCrowdData(crowd *outbound_crowd.OutboundCrowd) *pb.GetCrowd {
	data := &pb.GetCrowd{
		Id:              crowd.Id,
		CrowdName:       crowd.CrowdName,
		Type:            crowd.Type,
		Status:          crowd.Status,
		Version:         crowd.Version,
		PhoneType:       crowd.PhoneType,
		EveryCompanyNum: crowd.EveryCompanyNum,
		IsLandOpen:      crowd.IsLandOpen,
		IsBuildingOpen:  crowd.IsBuildingOpen,
		IsSaleOpen:      crowd.IsSaleOpen,
		CompanyTotal:    crowd.CompanyTotal,
		ContactTotal:    crowd.ContactTotal,
		LogicType:       crowd.LogicType,
		IsBidOpen:       crowd.IsBidOpen,
	}
	if crowd.AreaCode == "" {
		data.AreaCode = []string{}
	} else {
		data.AreaCode = strings.Split(crowd.AreaCode, ",")
	}
	if crowd.AreaName == "" {
		data.AreaName = []string{}
	} else {
		data.AreaName = strings.Split(crowd.AreaName, ",")
	}
	if crowd.WinbidKeyword == "" {
		data.WinbidKeyword = make([]string, 0)
	} else {
		data.WinbidKeyword = strings.Split(crowd.WinbidKeyword, ",")
	}
	if crowd.CompanyKeyword == "" {
		data.CompanyKeyword = []string{}
	} else {
		data.CompanyKeyword = strings.Split(crowd.CompanyKeyword, ",")
	}
	if crowd.BidKeyword == "" {
		data.BidKeyword = []string{}
	} else {
		data.BidKeyword = strings.Split(crowd.BidKeyword, ",")
	}
	if crowd.BidKeywordExclude == "" {
		data.BidKeywordExclude = []string{}
	} else {
		data.BidKeywordExclude = strings.Split(crowd.BidKeywordExclude, ",")
	}
	if crowd.LandUsage == "" {
		data.LandUsage = []string{}
	} else {
		data.LandUsage = strings.Split(crowd.LandUsage, ",")
	}
	if crowd.BuildingType == "" {
		data.BuildingType = []string{}
	} else {
		data.BuildingType = strings.Split(crowd.BuildingType, ",")
	}
	if crowd.SaleType == "" {
		data.SaleType = []string{}
	} else {
		data.SaleType = strings.Split(crowd.SaleType, ",")
	}
	if crowd.ProjectKeyword == "" {
		data.ProjectKeyword = []string{}
	} else {
		data.ProjectKeyword = strings.Split(crowd.ProjectKeyword, ",")
	}
	if crowd.LandKeyword == "" {
		data.LandKeyword = []string{}
	} else {
		data.LandKeyword = strings.Split(crowd.LandKeyword, ",")
	}
	if crowd.BuildingKeyword == "" {
		data.BuildingKeyword = []string{}
	} else {
		data.BuildingKeyword = strings.Split(crowd.BuildingKeyword, ",")
	}
	if crowd.SaleKeyword == "" {
		data.SaleKeyword = []string{}
	} else {
		data.SaleKeyword = strings.Split(crowd.SaleKeyword, ",")
	}
	if crowd.CompanyType == "" {
		data.CompanyType = []string{}
	} else {
		data.CompanyType = strings.Split(crowd.CompanyType, ",")
	}
	if crowd.CompanyKeywordExclude == "" {
		data.CompanyKeywordExclude = []string{}
	} else {
		data.CompanyKeywordExclude = strings.Split(crowd.CompanyKeywordExclude, ",")
	}

	//日期
	if crowd.WinbidDateStart.Valid == false {
		data.WinbidDateStart = ""
	} else if len(crowd.WinbidDateStart.Time.String()) >= 19 {
		data.WinbidDateStart = crowd.WinbidDateStart.Time.String()[0:19]
	}

	if crowd.WinbidDateEnd.Valid == false {
		data.WinbidDateEnd = ""
	} else if len(crowd.WinbidDateEnd.Time.String()) >= 19 {
		data.WinbidDateEnd = crowd.WinbidDateEnd.Time.String()[0:19]
	}

	if crowd.BidDateStart.Valid == false {
		data.BidDateStart = ""
	} else if len(crowd.BidDateStart.Time.String()) >= 19 {
		data.BidDateStart = crowd.BidDateStart.Time.String()[0:19]
	}

	if crowd.BidDateEnd.Valid == false {
		data.BidDateEnd = ""
	} else if len(crowd.BidDateEnd.Time.String()) >= 19 {
		data.BidDateEnd = crowd.BidDateEnd.Time.String()[0:19]
	}

	if crowd.LandDateStart.Valid == false {
		data.LandDateStart = ""
	} else if len(crowd.LandDateStart.Time.String()) >= 19 {
		data.LandDateStart = crowd.LandDateStart.Time.String()[0:19]
	}

	if crowd.LandDateEnd.Valid == false {
		data.LandDateEnd = ""
	} else if len(crowd.LandDateEnd.Time.String()) >= 19 {
		data.LandDateEnd = crowd.LandDateEnd.Time.String()[0:19]
	}

	if crowd.BuildingDateStart.Valid == false {
		data.BuildingDateStart = ""
	} else if len(crowd.BuildingDateStart.Time.String()) >= 19 {
		data.BuildingDateStart = crowd.BuildingDateStart.Time.String()[0:19]
	}

	if crowd.BuildingDateEnd.Valid == false {
		data.BuildingDateEnd = ""
	} else if len(crowd.BuildingDateEnd.Time.String()) >= 19 {
		data.BuildingDateEnd = crowd.BuildingDateEnd.Time.String()[0:19]
	}

	if crowd.SaleDateStart.Valid == false {
		data.SaleDateStart = ""
	} else if len(crowd.SaleDateStart.Time.String()) >= 19 {
		data.SaleDateStart = crowd.SaleDateStart.Time.String()[0:19]
	}

	if crowd.SaleDateEnd.Valid == false {
		data.SaleDateEnd = ""
	} else if len(crowd.SaleDateEnd.Time.String()) >= 19 {
		data.SaleDateEnd = crowd.SaleDateEnd.Time.String()[0:19]
	}

	if len(crowd.CreatedOn.String()) >= 19 {
		data.CreatedOn = crowd.CreatedOn.String()[0:19]
	}
	data.CreatedBy = crowd.CreatedBy

	return data
}

// GetCrowdDetail 人群详情
func (s *outboundCrowdService) GetCrowdDetail(ctx context.Context, request *pb.GetCrowdDetailRequest) (*pb.GetCrowdDetailResponse, error) {
	crowd, err := s.outboundCrowdRepos.GetOutboundCrowd(ctx, request.Id)
	if err != nil {
		stark.Logger.Errorf(ctx, "GetCrowdDetail 获取人群详情,err:%s", err.Error())
	}
	data := s.dealCrowdData(crowd)
	res := &pb.GetCrowdDetailResponse{
		Data: data,
	}
	return res, nil
}

// AddCrowd 新增、保存人群
func (s *outboundCrowdService) AddCrowd(ctx context.Context, request *pb.AddCrowdRequest) (*pb.AddCrowdResponse, error) {
	if request.CrowdName == "" || request.Type == "" {
		return nil, ykerrcode.TogRPCError(ykerrcode.INVALID_PARAMS, "保存人群，参数缺失")
	}
	metaUserInfo := usermetadata.GetMetaUserInfo(ctx)
	crowd := &outbound_crowd.OutboundCrowd{}
	if request.Id != 0 { //修改
		crowdRow, err := s.outboundCrowdRepos.GetOutboundCrowd(ctx, request.Id)
		if err != nil {
			stark.Logger.Errorf(ctx, "GetCrowdDetail 获取人群详情,err:%s", err.Error())
			return nil, err
		}
		if crowdRow == nil || crowdRow.Id == 0 {
			return nil, errors.New("人群包不存在或已被删除")
		}

		crowdExist, err := s.outboundCrowdRepos.GetOutboundCrowdByName(ctx, request.CrowdName)
		if err != nil {
			stark.Logger.Errorf(ctx, "GetOutboundCrowdByName 获取人群,err:%s", err.Error())
			return nil, err
		}
		if crowdExist.CrowdName == request.CrowdName && crowdRow.Id != crowdExist.Id {
			return nil, ykerrcode.TogRPCError(ykerrcode.INVALID_PARAMS, "人群名称已存在，请重新输入")
		}

		crowdRow.Version += 1 //每次更新，版本号都加一
		crowd.ModifiedBy = metaUserInfo.UserName
		crowd = crowdRow
	} else { //新增
		//判断名称重复
		crowdRow, err := s.outboundCrowdRepos.GetOutboundCrowdByName(ctx, request.CrowdName)
		if err != nil {
			stark.Logger.Errorf(ctx, "GetOutboundCrowdByName 获取人群,err:%s", err.Error())
			return nil, err
		}
		if crowdRow.CrowdName == request.CrowdName {
			return nil, ykerrcode.TogRPCError(ykerrcode.INVALID_PARAMS, "人群名称已存在，请重新输入")
		}
		//判断RPA人群，唯一
		if request.Type == constants.CrowdTypeRpa {
			total, crowdRpa, err := s.outboundCrowdRepos.GetOutboundCrowdRpa(ctx)
			if err != nil {
				stark.Logger.Errorf(ctx, "GetOutboundCrowdRpa 获取rpa人群,err:%s", err.Error())
				return nil, err
			}
			if total > 0 && crowdRpa.CrowdName != request.CrowdName {
				return nil, ykerrcode.TogRPCError(ykerrcode.INVALID_PARAMS, "rpa类型的任务只能有一个")
			}
		}
		crowd.Version = 0
		crowd.Type = request.Type
		crowd.CreatedBy = metaUserInfo.UserName
	}
	crowd.CrowdName = request.CrowdName
	crowd.Status = 1
	crowd.AreaCode = strings.Join(request.AreaCode, ",")
	crowd.AreaName = strings.Join(request.AreaName, ",")
	crowd.WinbidKeyword = strings.Join(request.WinbidKeyword, ",")
	crowd.CompanyKeyword = strings.Join(request.CompanyKeyword, ",")
	crowd.WinbidDateStart = utils.StringToSqlTime(request.WinbidDateStart)
	crowd.WinbidDateEnd = utils.StringToSqlTime(request.WinbidDateEnd)
	crowd.PhoneType = request.PhoneType
	crowd.EveryCompanyNum = request.EveryCompanyNum
	crowd.BidKeyword = strings.Join(request.BidKeyword, ",")
	crowd.BidKeywordExclude = strings.Join(request.BidKeywordExclude, ",")
	crowd.BidDateStart = utils.StringToSqlTime(request.BidDateStart)
	crowd.BidDateEnd = utils.StringToSqlTime(request.BidDateEnd)
	crowd.IsLandOpen = request.IsLandOpen
	crowd.LandUsage = strings.Join(request.LandUsage, ",")
	crowd.LandDateStart = utils.StringToSqlTime(request.LandDateStart)
	crowd.LandDateEnd = utils.StringToSqlTime(request.LandDateEnd)
	crowd.IsBuildingOpen = request.IsBuildingOpen
	crowd.BuildingType = strings.Join(request.BuildingType, ",")
	crowd.BuildingDateStart = utils.StringToSqlTime(request.BuildingDateStart)
	crowd.BuildingDateEnd = utils.StringToSqlTime(request.BuildingDateEnd)
	crowd.IsSaleOpen = request.IsSaleOpen
	crowd.SaleType = strings.Join(request.SaleType, ",")
	crowd.SaleDateStart = utils.StringToSqlTime(request.SaleDateStart)
	crowd.SaleDateEnd = utils.StringToSqlTime(request.SaleDateEnd)
	//crowd.ProjectKeyword = strings.Join(request.ProjectKeyword, ",")
	crowd.CompanyTotal = request.CompanyTotal
	crowd.ContactTotal = request.ContactTotal
	crowd.LogicType = request.LogicType
	crowd.IsBidOpen = request.IsBidOpen
	crowd.LandKeyword = strings.Join(request.LandKeyword, ",")
	crowd.BuildingKeyword = strings.Join(request.BuildingKeyword, ",")
	crowd.SaleKeyword = strings.Join(request.SaleKeyword, ",")
	crowd.CompanyType = strings.Join(request.CompanyType, ",")
	crowd.CompanyKeywordExclude = strings.Join(request.CompanyKeywordExclude, ",")

	res := &pb.AddCrowdResponse{}
	if crowd != nil && crowd.Id != 0 {
		err := s.outboundCrowdRepos.SaveOutboundCrowd(ctx, crowd)
		if err != nil {
			stark.Logger.Errorf(ctx, "SaveOutboundCrowd 保存人群,err:%s", err.Error())
			return nil, err
		}
		res.Id = crowd.Id
		res.NewCrowd = false
	} else {
		autoId, err := s.outboundCrowdRepos.AddOutboundCrowd(ctx, crowd)
		if err != nil {
			stark.Logger.Errorf(ctx, "AddOutboundCrowd 新增人群,err:%s", err.Error())
			return nil, err
		}
		res.Id = autoId
		res.NewCrowd = true
	}

	//人群包新增或编辑成功，触发异步拉取人群包数据
	err := s.asyncSaveCrowd(ctx, res.Id)
	if err != nil {
		return nil, err
	}

	return res, nil
}

// DeleteCrowd 删除人群
func (s *outboundCrowdService) DeleteCrowd(ctx context.Context, request *pb.DeleteCrowdRequest) (*pb.DeleteCrowdResponse, error) {
	isDelete, err := s.outboundCrowdRepos.DeleteCrowd(ctx, request.Id)
	if err != nil {
		stark.Logger.Errorf(ctx, "DeleteCrowd 删除人群详情,err:%s", err.Error())
	}
	res := &pb.DeleteCrowdResponse{}
	if isDelete {
		res.Id = request.Id
	}
	return res, nil
}

// GetCrowdByWinbid 获取中标人群列表
func (s *outboundCrowdService) GetCrowdByWinbid(ctx context.Context, request *pb.GetCrowdByWinbidRequest) (*pb.GetCrowdByWinbidResponse, error) {
	if request.EveryCompanyNum == 0 {
		request.EveryCompanyNum = 2
	}
	//数据服务请求参数
	bigDataRequest := &bigdataRemote.GetCrowdByWinbidRequest{
		PageNum:               request.Page,
		PageSize:              request.PageSize,
		WinbidDateStart:       request.WinbidDateStart,
		WinbidDateEnd:         request.WinbidDateEnd,
		EveryCompanyNum:       request.EveryCompanyNum,
		AreaCode:              request.AreaCode,
		WinbidKeyword:         request.WinbidKeyword,
		CompanyKeyword:        request.CompanyKeyword,
		CompanyKeywordExclude: request.CompanyKeywordExclude,
	}
	//拼接 like 查询的 % 符号
	newWinbidKeyword := make([]string, 0)
	for _, v := range bigDataRequest.WinbidKeyword {
		v = "%" + v + "%"
		newWinbidKeyword = append(newWinbidKeyword, v)
	}
	bigDataRequest.WinbidKeyword = newWinbidKeyword

	newCompanyKeyword := make([]string, 0)
	for _, v := range bigDataRequest.CompanyKeyword {
		v = "%" + v + "%"
		newCompanyKeyword = append(newCompanyKeyword, v)
	}
	bigDataRequest.CompanyKeyword = newCompanyKeyword

	newCompanyKeywordExclude := make([]string, 0)
	for _, v := range bigDataRequest.CompanyKeywordExclude {
		v = "%" + v + "%"
		newCompanyKeywordExclude = append(newCompanyKeywordExclude, v)
	}
	bigDataRequest.CompanyKeywordExclude = newCompanyKeywordExclude

	//多协程获取人群列表、联系人数量
	crowdListData := &bigdataRemote.GetCrowdByWinbidData{}
	crowdListTotalData := &bigdataRemote.GetCrowdTotalByWinbidData{}
	bigDataTotalRequest := &bigdataRemote.GetCrowdTotalByWinbidRequest{}
	err := simplecopier.CopyToStruct(bigDataTotalRequest, bigDataRequest)
	if err != nil {
		stark.Logger.Errorf(ctx, "结构体赋值失败,err:%s", err.Error())
	}
	wg := sync.WaitGroup{}
	for i := 0; i <= 1; i++ {
		wg.Add(1)
		//1、联系人数量
		if i == 0 {
			go func(ctx2 context.Context, request *bigdataRemote.GetCrowdTotalByWinbidRequest, logicType string) {
				totalData, err := s.bigDataServiceRepo.GetCrowdTotalByWinbid(ctx, request, logicType)
				if err != nil {
					stark.Logger.Errorf(ctx, "bigdata GetCrowdTotalByWinbid,err:%s", err.Error())
				}
				crowdListTotalData = totalData

				wg.Done()
			}(ctx, bigDataTotalRequest, request.LogicType)
		}
		//2、人群列表
		if i == 1 {
			go func(ctx2 context.Context, request *bigdataRemote.GetCrowdByWinbidRequest, logicType string) {
				list, err := s.bigDataServiceRepo.GetCrowdByWinbid(ctx, request, logicType)
				if err != nil {
					stark.Logger.Errorf(ctx, "bigdata GetCrowdByWinbid,err:%s", err.Error())
				}
				crowdListData = list

				wg.Done()
			}(ctx, bigDataRequest, request.LogicType)
		}
	}
	wg.Wait()

	//输出数据
	if crowdListData != nil && crowdListData.Total > 0 {
		//返回结果
		result := &pb.GetCrowdByWinbidResponse{
			CompanyTotal: crowdListData.Total,
		}
		crowdByWinbidList := make([]*pb.CrowdByWinbidData, 0)

		for _, item := range crowdListData.List {
			//根据phone_type联系人类型，取不同的手机号
			if request.ContactType == "手机" && item.ContactMobileList != "" {
				err = json.Unmarshal([]byte(item.ContactMobileList), &item.ContactListArr)
				if err != nil {
					stark.Logger.Errorf(ctx, "json Unmarshal ,err:%s", err.Error())
				}
			} else if request.ContactType == "座机" && item.ContactFixedList != "" {
				err = json.Unmarshal([]byte(item.ContactFixedList), &item.ContactListArr)
				if err != nil {
					stark.Logger.Errorf(ctx, "json Unmarshal ,err:%s", err.Error())
				}
			} else if item.ContactList != "" {
				//手机和座机
				err = json.Unmarshal([]byte(item.ContactList), &item.ContactListArr)
				if err != nil {
					stark.Logger.Errorf(ctx, "json Unmarshal ,err:%s", err.Error())
				}
			}

			//根据every_company_num控制数量
			if int(request.EveryCompanyNum) < len(item.ContactListArr) {
				item.ContactListArr = item.ContactListArr[:request.EveryCompanyNum]
			}
			var newContactListArr []*pb.ContactList
			for _, v := range item.ContactListArr {
				data := &pb.ContactList{
					Name:        v.Name,
					PhoneNumber: v.PhoneNumber,
				}
				newContactListArr = append(newContactListArr, data)
			}
			//赋值
			crowdByWinbidItem := &pb.CrowdByWinbidData{
				SupplierName:   item.SupplierName,
				OrganizingCode: item.OrganizingCode,
				CoopPrjName:    item.CoopPrjName,
				CoopProvince:   item.CoopProvince,
				CoopCity:       item.CoopCity,
				ContactList:    newContactListArr,
			}

			crowdByWinbidList = append(crowdByWinbidList, crowdByWinbidItem)
		}
		result.List = crowdByWinbidList

		//联系人数量
		if len(crowdListTotalData.List) > 0 {
			if request.ContactType == "手机" {
				result.ContactTotal = crowdListTotalData.List[0].ParamMobileNum
			} else if request.ContactType == "座机" {
				result.ContactTotal = crowdListTotalData.List[0].ParamFixedNum
			} else {
				result.ContactTotal = crowdListTotalData.List[0].ParamAllNum
			}
		}

		return result, nil
	} else {
		return &pb.GetCrowdByWinbidResponse{}, nil
	}

}

// GetCrowdByDeveloper 获取甲方单位人群列表
func (s *outboundCrowdService) GetCrowdByDeveloper(ctx context.Context, request *pb.GetCrowdByDeveloperRequest) (*pb.GetCrowdByDeveloperResponse, error) {
	if request.EveryCompanyNum == 0 {
		request.EveryCompanyNum = 2
	}
	//如果未勾选单项数据，则置空搜索条件
	if request.IsBidOpen == 0 {
		request.BidKeywordExclude = []string{}
		request.BidKeyword = []string{}
		request.BidDateStart = ""
		request.BidDateEnd = ""
	}
	if request.IsLandOpen == 0 {
		request.LandKeyword = []string{}
		request.LandUsage = []string{}
		request.LandDateStart = ""
		request.LandDateEnd = ""
	}
	if request.IsBuildingOpen == 0 {
		request.BuildingType = []string{}
		request.BuildingKeyword = []string{}
		request.BuildingDateStart = ""
		request.BuildingDateEnd = ""
	}
	if request.IsSaleOpen == 0 {
		request.SaleType = []string{}
		request.SaleKeyword = []string{}
		request.SaleDateStart = ""
		request.SaleDateEnd = ""
	}
	//数据服务请求参数
	bigDataRequest := &bigdataRemote.GetCrowdByDeveloperRequest{
		PageNum:               request.Page,
		PageSize:              request.PageSize,
		BidDateStart:          request.BidDateStart,
		BidDateEnd:            request.BidDateEnd,
		LandDateStart:         request.LandDateStart,
		LandDateEnd:           request.LandDateEnd,
		BuildingDateStart:     request.BuildingDateStart,
		BuildingDateEnd:       request.BuildingDateEnd,
		SaleDateStart:         request.SaleDateStart,
		SaleDateEnd:           request.SaleDateEnd,
		EveryCompanyNum:       request.EveryCompanyNum,
		AreaCode:              request.AreaCode,
		BidKeyword:            request.BidKeyword,
		BidKeywordExclude:     request.BidKeywordExclude,
		BuildingType:          request.BuildingType,
		SaleType:              request.SaleType,
		LandUsage:             request.LandUsage,
		CompanyType:           request.CompanyType,
		CompanyKeyword:        request.CompanyKeyword,
		CompanyKeywordExclude: request.CompanyKeywordExclude,
		LandKeyword:           request.LandKeyword,
		BuildingKeyword:       request.BuildingKeyword,
		SaleKeyword:           request.SaleKeyword,
	}
	//关键词加上 % 符号
	newBidKeyword := make([]string, 0)
	for _, v := range bigDataRequest.BidKeyword {
		v = "%" + v + "%"
		newBidKeyword = append(newBidKeyword, v)
	}
	bigDataRequest.BidKeyword = newBidKeyword

	newBidKeywordExclude := make([]string, 0)
	for _, v := range bigDataRequest.BidKeywordExclude {
		v = "%" + v + "%"
		newBidKeywordExclude = append(newBidKeywordExclude, v)
	}
	bigDataRequest.BidKeywordExclude = newBidKeywordExclude

	newCompanyKeyword := make([]string, 0)
	for _, v := range bigDataRequest.CompanyKeyword {
		v = "%" + v + "%"
		newCompanyKeyword = append(newCompanyKeyword, v)
	}
	bigDataRequest.CompanyKeyword = newCompanyKeyword

	newCompanyKeywordExclude := make([]string, 0)
	for _, v := range bigDataRequest.CompanyKeywordExclude {
		v = "%" + v + "%"
		newCompanyKeywordExclude = append(newCompanyKeywordExclude, v)
	}
	bigDataRequest.CompanyKeywordExclude = newCompanyKeywordExclude

	newLandKeyword := make([]string, 0)
	for _, v := range bigDataRequest.LandKeyword {
		v = "%" + v + "%"
		newLandKeyword = append(newLandKeyword, v)
	}
	bigDataRequest.LandKeyword = newLandKeyword

	newBuildingKeyword := make([]string, 0)
	for _, v := range bigDataRequest.BuildingKeyword {
		v = "%" + v + "%"
		newBuildingKeyword = append(newBuildingKeyword, v)
	}
	bigDataRequest.BuildingKeyword = newBuildingKeyword

	newSaleKeyword := make([]string, 0)
	for _, v := range bigDataRequest.SaleKeyword {
		v = "%" + v + "%"
		newSaleKeyword = append(newSaleKeyword, v)
	}
	bigDataRequest.SaleKeyword = newSaleKeyword

	dataType := make([]string, 0)
	if request.IsBidOpen == 1 {
		dataType = append(dataType, constants.CrowdDeveloperDataTypeBid)
	}
	if request.IsLandOpen == 1 {
		dataType = append(dataType, constants.CrowdDeveloperDataTypeLand)
	}
	if request.IsBuildingOpen == 1 {
		dataType = append(dataType, constants.CrowdDeveloperDataTypeBuild)
	}
	if request.IsSaleOpen == 1 {
		dataType = append(dataType, constants.CrowdDeveloperDataTypeSale)
	}
	if len(dataType) == 0 { //如果没有数据种类，则传-1，不返回任何数据
		dataType = append(dataType, "-1")
	}
	bigDataRequest.DataType = dataType

	//多协程获取人群列表、联系人数量
	crowdListData := &bigdataRemote.GetCrowdByDeveloperData{}
	crowdListTotalData := &bigdataRemote.GetCrowdTotalByDeveloperData{}
	bigDataTotalRequest := &bigdataRemote.GetCrowdTotalByDeveloperRequest{}
	err := simplecopier.CopyToStruct(bigDataTotalRequest, bigDataRequest)
	if err != nil {
		stark.Logger.Errorf(ctx, "结构体赋值失败,err:%s", err.Error())
	}
	wg := sync.WaitGroup{}
	for i := 0; i <= 1; i++ {
		wg.Add(1)
		//1、联系人数量
		if i == 0 {
			go func(ctx2 context.Context, request *bigdataRemote.GetCrowdTotalByDeveloperRequest, logicType string) {
				totalData, err := s.bigDataServiceRepo.GetCrowdTotalByDeveloper(ctx, request, logicType)
				if err != nil {
					stark.Logger.Errorf(ctx, "bigdata GetCrowdTotalByDeveloper,err:%s", err.Error())
				}
				crowdListTotalData = totalData

				wg.Done()
			}(ctx, bigDataTotalRequest, request.LogicType)
		}
		//2、人群列表
		if i == 1 {
			go func(ctx2 context.Context, request *bigdataRemote.GetCrowdByDeveloperRequest, logicType string) {
				list, err := s.bigDataServiceRepo.GetCrowdByDeveloper(ctx, request, logicType)
				if err != nil {
					stark.Logger.Errorf(ctx, "bigdata GetCrowdByDeveloper,err:%s", err.Error())
				}
				crowdListData = list

				wg.Done()
			}(ctx, bigDataRequest, request.LogicType)
		}
	}
	wg.Wait()

	//输出数据
	if crowdListData != nil && crowdListData.Total > 0 {
		//返回结果
		result := &pb.GetCrowdByDeveloperResponse{
			CompanyTotal: crowdListData.Total,
		}
		crowdByDeveloperList := make([]*pb.CrowdByDeveloperData, 0)
		//遍历
		for _, item := range crowdListData.List {
			//根据phone_type联系人类型，取不同的手机号
			if request.ContactType == "手机" && item.ContactMobileList != "" {
				err = json.Unmarshal([]byte(item.ContactMobileList), &item.ContactListArr)
				if err != nil {
					stark.Logger.Errorf(ctx, "json Unmarshal ,err:%s", err.Error())
				}
			} else if request.ContactType == "座机" && item.ContactFixedList != "" {
				err = json.Unmarshal([]byte(item.ContactFixedList), &item.ContactListArr)
				if err != nil {
					stark.Logger.Errorf(ctx, "json Unmarshal ,err:%s", err.Error())
				}
			} else if item.ContactList != "" {
				err = json.Unmarshal([]byte(item.ContactList), &item.ContactListArr)
				if err != nil {
					stark.Logger.Errorf(ctx, "json Unmarshal ,err:%s", err.Error())
				}
			}

			//根据every_company_num控制数量
			if int(request.EveryCompanyNum) < len(item.ContactListArr) {
				item.ContactListArr = item.ContactListArr[:request.EveryCompanyNum]
			}
			newContactListArr := make([]*pb.ContactList, 0)
			for k, v := range item.ContactListArr {
				if (int32(k)) < request.EveryCompanyNum {
					data := &pb.ContactList{
						Name:        v.Name,
						PhoneNumber: v.PhoneNumber,
					}
					newContactListArr = append(newContactListArr, data)
				}
			}

			//赋值
			crowdByDeveloperItem := &pb.CrowdByDeveloperData{
				DeveloperName:           item.DeveloperName,
				DeveloperOrganizingCode: item.DeveloperOrganizingCode,
				TakeLandCnt_1Year:       item.TakeLandCnt_1Year,
				SellProjectCnt_1Year:    item.SellProjectCnt_1Year,
				CommencePermitCnt_1Year: item.CommencePermitCnt_1Year,
				PurchaseDemandCnt_1Year: item.PurchaseDemandCnt_1Year,
				ContactList:             newContactListArr,
			}
			crowdByDeveloperList = append(crowdByDeveloperList, crowdByDeveloperItem)
		}

		//联系人数量
		if len(crowdListTotalData.List) > 0 {
			if request.ContactType == "手机" {
				result.ContactTotal = crowdListTotalData.List[0].ParamMobileNum
			} else if request.ContactType == "座机" {
				result.ContactTotal = crowdListTotalData.List[0].ParamFixedNum
			} else {
				result.ContactTotal = crowdListTotalData.List[0].ParamAllNum
			}
		}

		result.List = crowdByDeveloperList
		return result, nil
	} else {
		return &pb.GetCrowdByDeveloperResponse{}, nil
	}

}

// GetCrowdByRpa 获取甲方单位人群列表
func (s *outboundCrowdService) GetCrowdByRpa(ctx context.Context, request *pb.GetCrowdByRpaRequest) (*pb.GetCrowdByRpaResponse, error) {
	//数据服务请求参数
	bigDataRequest := &bigdataRemote.GetCrowdByRpaRequest{
		PageNum:    request.Page,
		PageSize:   request.PageSize,
		ProjectId:  request.ProjectId,
		Id:         request.Id,
		TenantCode: request.TenantCode,
	}
	crowdListData, err := s.bigDataServiceRepo.GetCrowdByRpa(ctx, bigDataRequest)

	if err != nil {
		stark.Logger.Errorf(ctx, "bigdata GetCrowdByRpa,err:%s", err.Error())
	}
	if crowdListData != nil && crowdListData.Total > 0 {
		//返回结果
		result := &pb.GetCrowdByRpaResponse{
			Total: crowdListData.Total,
		}
		crowdByRpaList := make([]*pb.CrowdByRpaData, 0)
		//遍历
		for _, item := range crowdListData.List {
			//赋值
			crowdByRpaItem := &pb.CrowdByRpaData{
				CompanyAddress: item.CompanyAddress,
				CompanyName:    item.CompanyName,
				Id:             item.Id,
				PersonName:     item.PersonName,
				PersonPhone:    item.PersonPhone,
				PersonPosition: item.PersonPosition,
				PersonRole:     item.PersonRole,
				PersonSexy:     item.PersonSexy,
				ProjectId:      item.ProjectId,
				SourceType:     item.SourceType,
				RccProjectName: item.RccProjectName,
				SrcId:          item.SrcId,
			}
			crowdByRpaList = append(crowdByRpaList, crowdByRpaItem)
		}

		result.List = crowdByRpaList
		//手机号查看次数、以及打码
		if request.ShowViewTimes {
			mobileList := make([]string, 0)
			metaUserInfo := usermetadata.GetMetaUserInfo(ctx)
			for _, contactValue := range result.List {
				if contactValue.PersonPhone != "" {
					mobileList = append(mobileList, contactValue.PersonPhone)
				}
			}
			if len(mobileList) > 0 {
				mobileViewTimes, err := s.opTelViewHistoryRepos.GetOpTelViewHistoryBatch(ctx, mobileList, metaUserInfo.TenantUserUid)
				if err != nil {
					stark.Logger.Error(ctx, "获取gfyx_optelviewhistory异常,err:", err)
					return result, err
				}
				for _, contactValue := range result.List {
					contactValue.ViewTimes = mobileViewTimes[contactValue.PersonPhone]
					if mobileViewTimes[contactValue.PersonPhone] <= 0 { //如果手机号，没有被查看过，则需要打码
						contactValue.PersonPhone = utils.GetMobileEncrypt(contactValue.PersonPhone)
					}
				}
			}
		}
		return result, nil
	} else {
		return &pb.GetCrowdByRpaResponse{}, nil
	}

}

// GetRpaContactMobile rpa联系人手机号
func (s *outboundCrowdService) GetRpaContactMobile(ctx context.Context, request *pb.GetRpaContactMobileRequest) (*pb.GetRpaContactMobileResponse, error) {
	//数据服务请求参数
	bigDataRequest := &bigdataRemote.GetCrowdByRpaRequest{
		Id:       request.Id,
		PageNum:  1,
		PageSize: 1000,
	}
	crowdListData, err := s.bigDataServiceRepo.GetCrowdByRpa(ctx, bigDataRequest)

	if err != nil {
		stark.Logger.Errorf(ctx, "bigdata GetCrowdByRpa,err:%s", err.Error())
	}
	if crowdListData != nil && crowdListData.Total > 0 {
		//返回结果
		result := &pb.GetRpaContactMobileResponse{}
		//遍历
		result.Data = &pb.CrowdByRpaData{
			CompanyAddress: crowdListData.List[0].CompanyAddress,
			CompanyName:    crowdListData.List[0].CompanyName,
			Id:             crowdListData.List[0].Id,
			PersonName:     crowdListData.List[0].PersonName,
			PersonPhone:    crowdListData.List[0].PersonPhone,
			PersonPosition: crowdListData.List[0].PersonPosition,
			PersonRole:     crowdListData.List[0].PersonRole,
			PersonSexy:     crowdListData.List[0].PersonSexy,
			ProjectId:      crowdListData.List[0].ProjectId,
			SourceType:     crowdListData.List[0].SourceType,
			RccProjectName: crowdListData.List[0].RccProjectName,
			SrcId:          crowdListData.List[0].SrcId,
		}
		//更新浏览次数
		if result.Data.PersonPhone != "" {
			metaUserInfo := usermetadata.GetMetaUserInfo(ctx)

			viewTelPhone, _ := s.opTelViewHistoryRepos.GetOpTelViewHistory(ctx, result.Data.PersonPhone, metaUserInfo.TenantUserUid)
			if viewTelPhone != nil && viewTelPhone.OpTelViewHistoryGUID == "" {
				viewTelPhone.ViewTimes = 0
				viewTelPhone.TelNumber = result.Data.PersonPhone
				viewTelPhone.CreatedGUID = metaUserInfo.TenantUserUid
				viewTelPhone.CreatedName = metaUserInfo.UserName
				err = s.opTelViewHistoryRepos.SaveOpTelViewHistory(ctx, viewTelPhone)
				if err != nil {
					stark.Logger.Error(ctx, "新增gfyx_optelviewhistory,err:", err)
				}

			}
			result.Data.ViewTimes = viewTelPhone.ViewTimes
			_, err = s.opTelViewHistoryRepos.UpdateViewTimes(ctx, result.Data.PersonPhone, metaUserInfo.TenantUserUid)
			if err != nil {
				stark.Logger.Error(ctx, "更新gfyx_optelviewhistory,err:", err)
			}
		}

		return result, nil
	} else {
		return &pb.GetRpaContactMobileResponse{}, nil
	}

}

// GetDeveloperCrowdById 根据人群id，获取中标人群列表数据
func (s *outboundCrowdService) GetDeveloperCrowdById(ctx context.Context, crowdId int32, page int32, pageSize int32) (*bigdataRemote.GetCrowdByDeveloperData, error) {
	crowdDetail, err := s.outboundCrowdRepos.GetOutboundCrowd(ctx, crowdId)
	if err != nil {
		stark.Logger.Errorf(ctx, "GetOutboundCrowd 获取人群详情,err:%s", err.Error())
	}
	if crowdDetail == nil || crowdDetail.Id == 0 {
		return &bigdataRemote.GetCrowdByDeveloperData{}, nil
	}
	//获取人群，数据服务请求
	bigDataRequest := &bigdataRemote.GetCrowdByDeveloperRequest{
		PageNum:         page,
		PageSize:        pageSize,
		EveryCompanyNum: crowdDetail.EveryCompanyNum,
	}
	if crowdDetail.AreaCode == "" {
		bigDataRequest.AreaCode = make([]string, 0)
	} else {
		bigDataRequest.AreaCode = strings.Split(crowdDetail.AreaCode, ",")
	}
	if crowdDetail.BidKeyword == "" {
		bigDataRequest.BidKeyword = make([]string, 0)
	} else {
		bigDataRequest.BidKeyword = strings.Split(crowdDetail.BidKeyword, ",")
	}
	if crowdDetail.BidKeywordExclude == "" {
		bigDataRequest.BidKeywordExclude = make([]string, 0)
	} else {
		bigDataRequest.BidKeywordExclude = strings.Split(crowdDetail.BidKeywordExclude, ",")
	}
	if crowdDetail.ProjectKeyword == "" {
		bigDataRequest.ProjectKeyword = make([]string, 0)
	} else {
		bigDataRequest.ProjectKeyword = strings.Split(crowdDetail.ProjectKeyword, ",")
	}
	if crowdDetail.BuildingType == "" {
		bigDataRequest.BuildingType = make([]string, 0)
	} else {
		bigDataRequest.BuildingType = strings.Split(crowdDetail.BuildingType, ",")
	}
	if crowdDetail.SaleType == "" {
		bigDataRequest.SaleType = make([]string, 0)
	} else {
		bigDataRequest.SaleType = strings.Split(crowdDetail.SaleType, ",")
	}
	if crowdDetail.LandUsage == "" {
		bigDataRequest.LandUsage = make([]string, 0)
	} else {
		bigDataRequest.LandUsage = strings.Split(crowdDetail.LandUsage, ",")
	}
	if crowdDetail.LandKeyword == "" {
		bigDataRequest.LandKeyword = make([]string, 0)
	} else {
		bigDataRequest.LandKeyword = strings.Split(crowdDetail.LandKeyword, ",")
	}
	if crowdDetail.BuildingKeyword == "" {
		bigDataRequest.BuildingKeyword = make([]string, 0)
	} else {
		bigDataRequest.BuildingKeyword = strings.Split(crowdDetail.BuildingKeyword, ",")
	}
	if crowdDetail.SaleKeyword == "" {
		bigDataRequest.SaleKeyword = make([]string, 0)
	} else {
		bigDataRequest.SaleKeyword = strings.Split(crowdDetail.SaleKeyword, ",")
	}
	if crowdDetail.CompanyType == "" {
		bigDataRequest.CompanyType = make([]string, 0)
	} else {
		bigDataRequest.CompanyType = strings.Split(crowdDetail.CompanyType, ",")
	}
	if crowdDetail.CompanyKeyword == "" {
		bigDataRequest.CompanyKeyword = make([]string, 0)
	} else {
		bigDataRequest.CompanyKeyword = strings.Split(crowdDetail.CompanyKeyword, ",")
	}
	if crowdDetail.CompanyKeywordExclude == "" {
		bigDataRequest.CompanyKeywordExclude = make([]string, 0)
	} else {
		bigDataRequest.CompanyKeywordExclude = strings.Split(crowdDetail.CompanyKeywordExclude, ",")
	}

	//招标发布时间
	if crowdDetail.BidDateStart.Valid == false {
		bigDataRequest.BidDateStart = ""
	} else if len(crowdDetail.BidDateStart.Time.String()) >= 19 {
		bigDataRequest.BidDateStart = crowdDetail.BidDateStart.Time.String()[0:19]
	}
	if crowdDetail.BidDateEnd.Valid == false {
		bigDataRequest.BidDateEnd = ""
	} else if len(crowdDetail.BidDateEnd.Time.String()) >= 19 {
		bigDataRequest.BidDateEnd = crowdDetail.BidDateEnd.Time.String()[0:19]
	}
	//拿地时间
	if crowdDetail.LandDateStart.Valid == false {
		bigDataRequest.LandDateStart = ""
	} else if len(crowdDetail.LandDateStart.Time.String()) >= 19 {
		bigDataRequest.LandDateStart = crowdDetail.LandDateStart.Time.String()[0:19]
	}
	if crowdDetail.LandDateEnd.Valid == false {
		bigDataRequest.LandDateEnd = ""
	} else if len(crowdDetail.LandDateEnd.Time.String()) >= 19 {
		bigDataRequest.LandDateEnd = crowdDetail.LandDateEnd.Time.String()[0:19]
	}
	//开工时间
	if crowdDetail.BuildingDateStart.Valid == false {
		bigDataRequest.BuildingDateStart = ""
	} else if len(crowdDetail.BuildingDateStart.Time.String()) >= 19 {
		bigDataRequest.BuildingDateStart = crowdDetail.BuildingDateStart.Time.String()[0:19]
	}
	if crowdDetail.BuildingDateEnd.Valid == false {
		bigDataRequest.BuildingDateEnd = ""
	} else if len(crowdDetail.BuildingDateEnd.Time.String()) >= 19 {
		bigDataRequest.BuildingDateEnd = crowdDetail.BuildingDateEnd.Time.String()[0:19]
	}
	//开盘时间
	if crowdDetail.SaleDateStart.Valid == false {
		bigDataRequest.SaleDateStart = ""
	} else if len(crowdDetail.SaleDateStart.Time.String()) >= 19 {
		bigDataRequest.SaleDateStart = crowdDetail.SaleDateStart.Time.String()[0:19]
	}
	if crowdDetail.SaleDateEnd.Valid == false {
		bigDataRequest.SaleDateEnd = ""
	} else if len(crowdDetail.SaleDateEnd.Time.String()) >= 19 {
		bigDataRequest.SaleDateEnd = crowdDetail.SaleDateEnd.Time.String()[0:19]
	}
	//关键词加上 % 符号
	newBidKeyword := make([]string, 0)
	for _, v := range bigDataRequest.BidKeyword {
		v = "%" + v + "%"
		newBidKeyword = append(newBidKeyword, v)
	}
	bigDataRequest.BidKeyword = newBidKeyword

	newBidKeywordExclude := make([]string, 0)
	for _, v := range bigDataRequest.BidKeywordExclude {
		v = "%" + v + "%"
		newBidKeywordExclude = append(newBidKeywordExclude, v)
	}
	bigDataRequest.BidKeywordExclude = newBidKeywordExclude

	newProjectKeyword := make([]string, 0)
	for _, v := range bigDataRequest.ProjectKeyword {
		v = "%" + v + "%"
		newProjectKeyword = append(newProjectKeyword, v)
	}
	bigDataRequest.ProjectKeyword = newProjectKeyword

	newLandKeyword := make([]string, 0)
	for _, v := range bigDataRequest.LandKeyword {
		v = "%" + v + "%"
		newLandKeyword = append(newLandKeyword, v)
	}
	bigDataRequest.LandKeyword = newLandKeyword

	newBuildingKeyword := make([]string, 0)
	for _, v := range bigDataRequest.BuildingKeyword {
		v = "%" + v + "%"
		newBuildingKeyword = append(newBuildingKeyword, v)
	}
	bigDataRequest.BuildingKeyword = newBuildingKeyword

	newSaleKeyword := make([]string, 0)
	for _, v := range bigDataRequest.SaleKeyword {
		v = "%" + v + "%"
		newSaleKeyword = append(newSaleKeyword, v)
	}
	bigDataRequest.SaleKeyword = newSaleKeyword

	newCompanyKeyword := make([]string, 0)
	for _, v := range bigDataRequest.CompanyKeyword {
		v = "%" + v + "%"
		newCompanyKeyword = append(newCompanyKeyword, v)
	}
	bigDataRequest.CompanyKeyword = newCompanyKeyword

	newCompanyKeywordExclude := make([]string, 0)
	for _, v := range bigDataRequest.CompanyKeywordExclude {
		v = "%" + v + "%"
		newCompanyKeywordExclude = append(newCompanyKeywordExclude, v)
	}
	bigDataRequest.CompanyKeywordExclude = newCompanyKeywordExclude

	dataType := make([]string, 0)
	if crowdDetail.IsBidOpen == 1 {
		dataType = append(dataType, constants.CrowdDeveloperDataTypeBid)
	}
	if crowdDetail.IsLandOpen == 1 {
		dataType = append(dataType, constants.CrowdDeveloperDataTypeLand)
	}
	if crowdDetail.IsBuildingOpen == 1 {
		dataType = append(dataType, constants.CrowdDeveloperDataTypeBuild)
	}
	if crowdDetail.IsSaleOpen == 1 {
		dataType = append(dataType, constants.CrowdDeveloperDataTypeSale)
	}
	if len(dataType) == 0 { //如果没有数据种类，则传-1，不返回任何数据
		dataType = append(dataType, "-1")
	}
	bigDataRequest.DataType = dataType

	//如果未勾选单项数据，则置空搜索条件
	if crowdDetail.IsBidOpen == 0 {
		bigDataRequest.BidKeywordExclude = []string{}
		bigDataRequest.BidKeyword = []string{}
		bigDataRequest.BidDateStart = ""
		bigDataRequest.BidDateEnd = ""
	}
	if crowdDetail.IsLandOpen == 0 {
		bigDataRequest.LandKeyword = []string{}
		bigDataRequest.LandUsage = []string{}
		bigDataRequest.LandDateStart = ""
		bigDataRequest.LandDateEnd = ""
	}
	if crowdDetail.IsBuildingOpen == 0 {
		bigDataRequest.BuildingType = []string{}
		bigDataRequest.BuildingKeyword = []string{}
		bigDataRequest.BuildingDateStart = ""
		bigDataRequest.BuildingDateEnd = ""
	}
	if crowdDetail.IsSaleOpen == 0 {
		bigDataRequest.SaleType = []string{}
		bigDataRequest.SaleKeyword = []string{}
		bigDataRequest.SaleDateStart = ""
		bigDataRequest.SaleDateEnd = ""
	}

	crowdListData, err := s.bigDataServiceRepo.GetCrowdByDeveloper(ctx, bigDataRequest, crowdDetail.LogicType)

	if err != nil {
		stark.Logger.Errorf(ctx, "bigdata GetCrowdByDeveloper,err:%s", err.Error())
	}
	if crowdListData != nil && crowdListData.Total > 0 {
		for _, item := range crowdListData.List {
			//根据phone_type联系人类型，取不同的手机号
			if crowdDetail.PhoneType == "手机" && item.ContactMobileList != "" {
				err = json.Unmarshal([]byte(item.ContactMobileList), &item.ContactListArr)
				if err != nil {
					stark.Logger.Errorf(ctx, "json Unmarshal ,err:%s", err.Error())
				}
			} else if crowdDetail.PhoneType == "座机" && item.ContactFixedList != "" {
				err = json.Unmarshal([]byte(item.ContactFixedList), &item.ContactListArr)
				if err != nil {
					stark.Logger.Errorf(ctx, "json Unmarshal ,err:%s", err.Error())
				}
			} else if item.ContactList != "" {
				err := json.Unmarshal([]byte(item.ContactList), &item.ContactListArr)
				if err != nil {
					stark.Logger.Errorf(ctx, "json Unmarshal ,err:%s", err.Error())
				}
			}
			//根据every_company_num控制数量
			if int(crowdDetail.EveryCompanyNum) < len(item.ContactListArr) {
				item.ContactListArr = item.ContactListArr[:crowdDetail.EveryCompanyNum]
			}
		}
	}
	return crowdListData, nil
}

// GetWinbidCrowdById 根据人群id，获取中标人群列表数据
func (s *outboundCrowdService) GetWinbidCrowdById(ctx context.Context, crowdId int32, page int32, pageSize int32) (*bigdataRemote.GetCrowdByWinbidData, error) {
	crowdDetail, err := s.outboundCrowdRepos.GetOutboundCrowd(ctx, crowdId)
	if err != nil {
		stark.Logger.Errorf(ctx, "GetOutboundCrowd 获取人群详情,err:%s", err.Error())
	}
	if crowdDetail == nil || crowdDetail.Id == 0 {
		return &bigdataRemote.GetCrowdByWinbidData{}, nil
	}
	//获取合作单位
	bigDataRequest := &bigdataRemote.GetCrowdByWinbidRequest{
		PageNum:  page,
		PageSize: pageSize,
	}
	if crowdDetail.AreaCode == "" {
		bigDataRequest.AreaCode = make([]string, 0)
	} else {
		bigDataRequest.AreaCode = strings.Split(crowdDetail.AreaCode, ",")
	}
	if crowdDetail.WinbidKeyword == "" {
		bigDataRequest.WinbidKeyword = make([]string, 0)
	} else {
		bigDataRequest.WinbidKeyword = strings.Split(crowdDetail.WinbidKeyword, ",")
	}
	if crowdDetail.CompanyKeyword == "" {
		bigDataRequest.CompanyKeyword = make([]string, 0)
	} else {
		bigDataRequest.CompanyKeyword = strings.Split(crowdDetail.CompanyKeyword, ",")
	}
	if crowdDetail.CompanyKeywordExclude == "" {
		bigDataRequest.CompanyKeywordExclude = make([]string, 0)
	} else {
		bigDataRequest.CompanyKeywordExclude = strings.Split(crowdDetail.CompanyKeywordExclude, ",")
	}

	if crowdDetail.WinbidDateStart.Valid == false {
		bigDataRequest.WinbidDateStart = ""
	} else if len(crowdDetail.WinbidDateStart.Time.String()) >= 19 {
		bigDataRequest.WinbidDateStart = crowdDetail.WinbidDateStart.Time.String()[0:19]
	}
	if crowdDetail.WinbidDateEnd.Valid == false {
		bigDataRequest.WinbidDateEnd = ""
	} else if len(crowdDetail.WinbidDateEnd.Time.String()) >= 19 {
		bigDataRequest.WinbidDateEnd = crowdDetail.WinbidDateEnd.Time.String()[0:19]
	}
	newWinbidKeyword := make([]string, 0)
	for _, v := range bigDataRequest.WinbidKeyword {
		v = "%" + v + "%"
		newWinbidKeyword = append(newWinbidKeyword, v)
	}
	bigDataRequest.WinbidKeyword = newWinbidKeyword

	newCompanyKeyword := make([]string, 0)
	for _, v := range bigDataRequest.CompanyKeyword {
		v = "%" + v + "%"
		newCompanyKeyword = append(newCompanyKeyword, v)
	}
	bigDataRequest.CompanyKeyword = newCompanyKeyword

	newCompanyKeywordExclude := make([]string, 0)
	for _, v := range bigDataRequest.CompanyKeywordExclude {
		v = "%" + v + "%"
		newCompanyKeywordExclude = append(newCompanyKeywordExclude, v)
	}
	bigDataRequest.CompanyKeywordExclude = newCompanyKeywordExclude

	crowdListData, err := s.bigDataServiceRepo.GetCrowdByWinbid(ctx, bigDataRequest, crowdDetail.LogicType)

	if err != nil {
		stark.Logger.Errorf(ctx, "bigdata GetCrowdByWinbid,err:%s", err.Error())
	}
	if crowdListData != nil && crowdListData.Total > 0 {
		for _, item := range crowdListData.List {
			//根据phone_type联系人类型，取不同的手机号
			if crowdDetail.PhoneType == "手机" && item.ContactMobileList != "" {
				err = json.Unmarshal([]byte(item.ContactMobileList), &item.ContactListArr)
				if err != nil {
					stark.Logger.Errorf(ctx, "json Unmarshal ,err:%s", err.Error())
				}
			} else if crowdDetail.PhoneType == "座机" && item.ContactFixedList != "" {
				err = json.Unmarshal([]byte(item.ContactFixedList), &item.ContactListArr)
				if err != nil {
					stark.Logger.Errorf(ctx, "json Unmarshal ,err:%s", err.Error())
				}
			} else if item.ContactList != "" {
				err = json.Unmarshal([]byte(item.ContactList), &item.ContactListArr)
				if err != nil {
					stark.Logger.Errorf(ctx, "json Unmarshal ,err:%s", err.Error())
				}
			}

			//根据every_company_num控制数量
			if int(crowdDetail.EveryCompanyNum) < len(item.ContactListArr) {
				item.ContactListArr = item.ContactListArr[:crowdDetail.EveryCompanyNum]
			}
		}
	}
	return crowdListData, nil
}

// CrowdDetailWinbid 人群详情：中标人群数据
func (s *outboundCrowdService) CrowdDetailWinbid(ctx context.Context, request *pb.CrowdDetailWinbidRequest) (*pb.CrowdDetailWinbidResponse, error) {
	crowdDetail, err := s.outboundCrowdRepos.GetOutboundCrowd(ctx, request.CrowdId)
	if err != nil {
		stark.Logger.Errorf(ctx, "GetOutboundCrowd 获取人群详情,err:%s", err.Error())
	}
	if crowdDetail == nil || crowdDetail.Id == 0 {
		return &pb.CrowdDetailWinbidResponse{}, nil
	}

	data, err := s.getPreviewDataByCrowdId(ctx, request.CrowdId)
	if err != nil {
		stark.Logger.Errorf(ctx, "CrowdDetailWinbid，人群包id：%+d，错误信息：%s", request.CrowdId, err.Error())
	}
	//超过5分钟未生成预览数据,返回异常
	if crowdDetail.Status == 1 && len(crowdDetail.ModifiedOn.String()) >= 19 {
		time1 := utils.StringToTime(crowdDetail.ModifiedOn.String()[0:19]).Unix()
		time2 := time.Now().Unix()
		if string(data) == "" && time2-time1 > 300 {
			stark.Logger.Infof(ctx, "长时间未生成预览数据,服务可能出现问题,time1:%s,time2:", time1, time2)
			return &pb.CrowdDetailWinbidResponse{}, ykerrcode.TogRPCError(errcode.COMMON_SMS_CODE_MAX_SEND, "长时间未生成预览数据，服务可能出现问题")
		}
	}

	if string(data) == "" {
		return &pb.CrowdDetailWinbidResponse{
			CompanyTotal: crowdDetail.CompanyTotal,
			ContactTotal: crowdDetail.ContactTotal,
		}, nil
	}

	var dataStruct = make([]*bigdataRemote.GetCrowdByWinbidItem, 0)
	err = json.Unmarshal(data, &dataStruct)
	if err != nil {
		stark.Logger.Errorf(ctx, "json Unmarshal ,err:%s", err.Error())
	}
	//数据分页、转换
	resData := make([]*pb.CrowdByWinbidData, 0)
	offset := (request.Page - 1) * request.PageSize
	for i, item := range dataStruct {
		if int32(i) >= offset && int32(i) < offset+request.PageSize {
			row := &pb.CrowdByWinbidData{
				SupplierName:   item.SupplierName,
				OrganizingCode: item.OrganizingCode,
				CoopPrjName:    item.CoopPrjName,
				CoopProvince:   item.CoopProvince,
				CoopCity:       item.CoopCity,
			}
			contactArr := make([]*pb.ContactList, 0)
			for _, c := range item.ContactListArr {
				contactArr = append(contactArr, &pb.ContactList{
					Name:        c.Name,
					PhoneNumber: c.PhoneNumber,
				})
			}
			row.ContactList = contactArr
			resData = append(resData, row)
		}
	}

	res := &pb.CrowdDetailWinbidResponse{
		CompanyTotal: crowdDetail.CompanyTotal,
		ContactTotal: crowdDetail.ContactTotal,
		List:         resData,
	}
	return res, nil

}

// CrowdDetailDeveloper 人群详情：甲方单位人群数据
func (s *outboundCrowdService) CrowdDetailDeveloper(ctx context.Context, request *pb.CrowdDetailDeveloperRequest) (*pb.CrowdDetailDeveloperResponse, error) {
	crowdDetail, err := s.outboundCrowdRepos.GetOutboundCrowd(ctx, request.CrowdId)
	if err != nil {
		stark.Logger.Errorf(ctx, "GetOutboundCrowd 获取人群详情,err:%s", err.Error())
	}
	if crowdDetail == nil || crowdDetail.Id == 0 {
		return &pb.CrowdDetailDeveloperResponse{}, nil
	}

	data, err := s.getPreviewDataByCrowdId(ctx, request.CrowdId)
	if err != nil {
		stark.Logger.Errorf(ctx, "CrowdDetailDeveloper，人群包id：%+d，错误信息：%s", request.CrowdId, err.Error())
	}
	//超过5分钟未生成预览数据,返回异常
	if crowdDetail.Status == 1 && len(crowdDetail.ModifiedOn.String()) >= 19 {
		time1 := utils.StringToTime(crowdDetail.ModifiedOn.String()[0:19]).Unix()
		time2 := time.Now().Unix()
		if string(data) == "" && time2-time1 > 300 {
			stark.Logger.Infof(ctx, "长时间未生成预览数据,服务可能出现问题,time1:%s,time2:", time1, time2)
			return &pb.CrowdDetailDeveloperResponse{}, ykerrcode.TogRPCError(errcode.COMMON_SMS_CODE_MAX_SEND, "长时间未生成预览数据，服务可能出现问题")
		}
	}

	if string(data) == "" {
		return &pb.CrowdDetailDeveloperResponse{
			CompanyTotal: crowdDetail.CompanyTotal,
			ContactTotal: crowdDetail.ContactTotal,
		}, nil
	}
	var dataStruct = make([]*bigdataRemote.GetCrowdByDeveloperItem, 0)
	err = json.Unmarshal(data, &dataStruct)
	if err != nil {
		stark.Logger.Errorf(ctx, "json Unmarshal ,err:%s", err.Error())
	}
	//数据分页、转换
	resData := make([]*pb.CrowdByDeveloperData, 0)
	offset := (request.Page - 1) * request.PageSize
	for i, item := range dataStruct {
		if int32(i) >= offset && int32(i) < offset+request.PageSize {
			row := &pb.CrowdByDeveloperData{
				DeveloperName:           item.DeveloperName,
				DeveloperOrganizingCode: item.DeveloperOrganizingCode,
				TakeLandCnt_1Year:       item.TakeLandCnt_1Year,
				SellProjectCnt_1Year:    item.SellProjectCnt_1Year,
				CommencePermitCnt_1Year: item.CommencePermitCnt_1Year,
				PurchaseDemandCnt_1Year: item.PurchaseDemandCnt_1Year,
			}
			contactArr := make([]*pb.ContactList, 0)
			for _, c := range item.ContactListArr {
				contactArr = append(contactArr, &pb.ContactList{
					Name:        c.Name,
					PhoneNumber: c.PhoneNumber,
				})
			}
			row.ContactList = contactArr
			resData = append(resData, row)
		}
	}

	res := &pb.CrowdDetailDeveloperResponse{
		CompanyTotal: crowdDetail.CompanyTotal,
		ContactTotal: crowdDetail.ContactTotal,
		List:         resData,
	}
	return res, nil

}

func (s *outboundCrowdService) asyncSaveCrowd(ctx context.Context, crowdId int32) error {
	newCtx, err := tenant_db.GetTenantBackgroundContext(ctx, "")
	if err != nil {
		return err
	}
	go func(ctx2 context.Context) {
		err = s.asyncRun(ctx2, crowdId)
		if err != nil {
			stark.Logger.Errorf(ctx2, "异步保存人群包是吧，人群包id：%+d，错误信息：%s", crowdId, err.Error())
		} else {
			stark.Logger.Infof(ctx2, "异步保存人群包成功，人群包id：%d", crowdId)
		}
	}(newCtx)
	return nil
}

func (s *outboundCrowdService) asyncRun(ctx context.Context, crowdId int32) error {
	//1.获取人群包的版本号
	crowdPo, err := s.outboundCrowdRepos.GetOutboundCrowd(ctx, crowdId)
	if err != nil {
		return err
	}
	if crowdPo == nil || crowdPo.Id == 0 {
		return errors.New("人群包不存在或已被删除")
	}

	srcVersion := crowdPo.Version
	operator := crowdPo.ModifiedBy
	tenantCode := authorize.GetTenantCode(ctx)
	business := constants.PathOutboundCrowd
	//2.分批分页查询数据，第一页的数据另外存一份，按原格式保存，用以预览
	pageInfo := utils.PageInfo{
		PageSize: 2000,
		Page:     1,
		Total:    0,
	}
	batchSize := 10000
	var customerInfoList []*baiying_remote.CustomerItem
	for {
		if crowdPo.Type == constants.CrowdTypeRpa {
			//rpc的人群包不需要存文件，每次都是拉最新的人群包数据
			break
		}
		//1.获取数据
		customerInfoList = []*baiying_remote.CustomerItem{}
		switch crowdPo.Type {
		case constants.CrowdTypeDeveloper:
			developerCrowdData, err := s.GetDeveloperCrowdById(ctx, crowdId, int32(pageInfo.Page), int32(pageInfo.PageSize))
			if err != nil {
				stark.Logger.Errorf(ctx, "longRun GetDeveloperCrowdById crowdId:%d, pageInfo:%+v, err:%s", crowdId, pageInfo, err.Error())
				return err
			}
			//
			if developerCrowdData != nil {
				pageInfo.Total = int64(developerCrowdData.Total)
				for _, item := range developerCrowdData.List {
					for _, info := range item.ContactListArr {
						name := ""
						// 如果item.DeveloperName和info.Name都不为空则用-将两个值拼接，否则则用不为空的那个值给name字段赋值
						if item.DeveloperName != "" && info.Name != "" {
							name = fmt.Sprintf("%s-%s", item.DeveloperName, info.Name)
						} else if item.DeveloperName != "" {
							name = item.DeveloperName
						} else if info.Name != "" {
							name = info.Name
						}
						customerInfoList = append(customerInfoList, &baiying_remote.CustomerItem{
							Phone: info.PhoneNumber,
							Name:  name,
						})
					}
				}
				if pageInfo.Page == 1 {
					//第一页的数据另外存一份，按原格式保存，用以预览
					bytesData, _ := json.Marshal(developerCrowdData.List)
					filePath, _, err := ossfile.PutOss(bytes.NewReader(bytesData), business, tenantCode, ".txt", 1)
					if err != nil {
						return err
					}
					newFilePo, err := s.fileRepo.SaveFile(ctx, &file.GfyxFilesPo{
						Business:   business,
						FileType:   ".txt",
						FileName:   "",
						FilePath:   filePath,
						FileSize:   int64(len(bytesData)),
						IsDeleted:  constants.IsDeletedFalse,
						CreatedOn:  time.Now(),
						CreatedBy:  operator,
						ModifiedOn: time.Now(),
						ModifiedBy: operator,
					})
					if err != nil {
						return err
					}
					_, _ = s.outboundCrowdRepos.AddOutboundCrowdFile(ctx, &outbound_crowd.OutboundCrowdFilePo{
						CrowdId:       crowdId,
						CrowdVersion:  crowdPo.Version,
						FileId:        newFilePo.Id,
						IsPreviewData: 1,
						CreatedBy:     operator,
						CreatedOn:     time.Now(),
						ModifiedBy:    operator,
						ModifiedOn:    time.Now(),
						IsDeleted:     constants.IsDeletedFalse,
					})
				}
			}
		case constants.CrowdTypeWinBid:
			winbidCrowdData, err := s.GetWinbidCrowdById(ctx, crowdId, int32(pageInfo.Page), int32(pageInfo.PageSize))
			if err != nil {
				stark.Logger.Errorf(ctx, "longRun GetWinbidCrowdById crowdId:%d, pageInfo:%+v, err:%s", crowdId, pageInfo, err.Error())
				return err
			}
			//
			if winbidCrowdData != nil {
				pageInfo.Total = int64(winbidCrowdData.Total)
				for _, item := range winbidCrowdData.List {
					for _, info := range item.ContactListArr {
						name := ""
						// 如果item.SupplierName和info.Name都不为空则用-将两个值拼接，否则则用不为空的那个值给name字段赋值
						if item.SupplierName != "" && info.Name != "" {
							name = fmt.Sprintf("%s-%s", item.SupplierName, info.Name)
						} else if item.SupplierName != "" {
							name = item.SupplierName
						} else if info.Name != "" {
							name = info.Name
						}
						customerInfoList = append(customerInfoList, &baiying_remote.CustomerItem{
							Phone: info.PhoneNumber,
							Name:  name,
						})
					}
				}
				if pageInfo.Page == 1 {
					//第一页的数据另外存一份，按原格式保存，用以预览
					bytesData, _ := json.Marshal(winbidCrowdData.List)
					filePath, _, err := ossfile.PutOss(bytes.NewReader(bytesData), business, tenantCode, ".txt", 1)
					if err != nil {
						return err
					}
					newFilePo, err := s.fileRepo.SaveFile(ctx, &file.GfyxFilesPo{
						Business:   business,
						FileType:   ".txt",
						FileName:   "",
						FilePath:   filePath,
						FileSize:   int64(len(bytesData)),
						IsDeleted:  constants.IsDeletedFalse,
						CreatedOn:  time.Now(),
						CreatedBy:  operator,
						ModifiedOn: time.Now(),
						ModifiedBy: operator,
					})
					if err != nil {
						return err
					}
					_, _ = s.outboundCrowdRepos.AddOutboundCrowdFile(ctx, &outbound_crowd.OutboundCrowdFilePo{
						CrowdId:       crowdId,
						CrowdVersion:  crowdPo.Version,
						FileId:        newFilePo.Id,
						IsPreviewData: 1,
						CreatedBy:     operator,
						CreatedOn:     time.Now(),
						ModifiedBy:    operator,
						ModifiedOn:    time.Now(),
						IsDeleted:     constants.IsDeletedFalse,
					})
				}
			}
		}

		customerListSize := len(customerInfoList)
		//2.保存数据至oss
		// 百应的导入接口限制单次1万条，所以存文件的时候，也按1万条分批
		for i := 0; i*batchSize < customerListSize; i++ {
			startPos := i * batchSize
			endPos := (i + 1) * batchSize
			if endPos > customerListSize {
				endPos = customerListSize
			}
			customerBytes, _ := json.Marshal(customerInfoList[startPos:endPos])
			filePath, _, err := ossfile.PutOss(bytes.NewReader(customerBytes), business, tenantCode, ".txt", 1)
			if err != nil {
				return err
			}
			newFilePo, err := s.fileRepo.SaveFile(ctx, &file.GfyxFilesPo{
				Business:   business,
				FileType:   ".txt",
				FileName:   "",
				FilePath:   filePath,
				FileSize:   int64(len(customerBytes)),
				IsDeleted:  constants.IsDeletedFalse,
				CreatedOn:  time.Now(),
				CreatedBy:  operator,
				ModifiedOn: time.Now(),
				ModifiedBy: operator,
			})
			if err != nil {
				return err
			}
			_, err = s.outboundCrowdRepos.AddOutboundCrowdFile(ctx, &outbound_crowd.OutboundCrowdFilePo{
				CrowdId:       crowdId,
				CrowdVersion:  srcVersion,
				FileId:        newFilePo.Id,
				IsPreviewData: 0,
				CreatedBy:     operator,
				CreatedOn:     time.Now(),
				ModifiedBy:    operator,
				ModifiedOn:    time.Now(),
				IsDeleted:     constants.IsDeletedFalse,
			})
			if err != nil {
				return err
			}
		}

		//3.写入runtime表数据
		_, _ = s.outboundCrowdRepos.AddOutboundCrowdRuntime(ctx, &outbound_crowd.OutboundCrowdRuntimePo{
			Id:           0,
			CrowdId:      crowdId,
			CrowdVersion: srcVersion,
			Total:        pageInfo.Total,
			Page:         pageInfo.Page,
			PageSize:     pageInfo.PageSize,
			CreatedBy:    operator,
			CreatedOn:    time.Now(),
			ModifiedBy:   operator,
			ModifiedOn:   time.Now(),
			IsDeleted:    constants.IsDeletedFalse,
		})
		//4.判断是否达到退出条件
		// 退出条件：全量数据拉取完成 or 人群包版本变化 or 人群包被删除 or 分页超过100000页（兜底策略，公司数据总量在200万左右，100000页足够了，避免无限死循环）
		crowdPo, err = s.outboundCrowdRepos.GetOutboundCrowd(ctx, crowdId)
		if err != nil {
			return err
		}
		if customerListSize == 0 || crowdPo == nil || crowdPo.Id == 0 || crowdPo.Version != srcVersion || pageInfo.Page > 100000 ||
			int64(pageInfo.Page)*int64(pageInfo.PageSize) > pageInfo.Total {
			break
		}
		pageInfo.Page++
	}
	//5.更新人群包状态
	_, err = s.outboundCrowdRepos.UpdateStatus(ctx, crowdId, constants.CrowdStatusDone)
	if err != nil {
		return err
	}
	return nil
}

func (s *outboundCrowdService) getPreviewDataByCrowdId(ctx context.Context, crowdId int32) ([]byte, error) {
	crowdPo, err := s.outboundCrowdRepos.GetOutboundCrowd(ctx, crowdId)
	if err != nil {
		return nil, err
	}

	crowdFileList, err := s.outboundCrowdRepos.GetOutboundCrowdFileByCondition(ctx,
		map[string]interface{}{"crowd_id": crowdId, "crowd_version": crowdPo.Version,
			"is_preview_data": 1, "is_deleted": constants.IsDeletedFalse})
	if err != nil {
		return nil, err
	}
	if len(crowdFileList) == 0 {
		return nil, nil
	}

	fileInfo, err := s.fileRepo.QueryById(ctx, crowdFileList[0].FileId)
	if err != nil {
		return nil, err
	}
	if fileInfo == nil {
		return nil, nil
	}
	fileDownloadUrl, err := ossfile.GetSignURL(fileInfo.FilePath)
	if err != nil {
		return nil, err
	}
	resp, err := http.Get(fileDownloadUrl)
	if err != nil {
		return nil, err
	}

	data, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	defer func() {
		_ = resp.Body.Close()
	}()

	return data, nil
}
